import sys
import inexact_newton
import optimizer_util
import trigonometric
import call_counter
import penalty_1
import extended_rosenbrock
import extended_fr
import l_bfgs
import l_bfgs_compact
import l_sr1

METHODS = {
    'IN1': inexact_newton.create_inexact_newton_fixed_eta(1e-4),
    'IN2': inexact_newton.create_inexact_newton_2(0.9, 2, 0.9),
    'L-BFGS5': l_bfgs.create(5),
    'L-BFGS9': l_bfgs.create(9),
    'L-BFGS15': l_bfgs.create(15),
    'L-BFGS5C': l_bfgs_compact.create(5),
    'L-BFGS9C': l_bfgs_compact.create(9),
    'L-BFGS15C': l_bfgs_compact.create(15),
    'L-SR1_5': l_sr1.create(5),
    'L-SR1_9': l_sr1.create(9),
    'L-SR1_15': l_sr1.create(15),
}

FUNCTION_BUILDERS = {
    'trigonometric': trigonometric.create,
    'penalty_1': penalty_1.create,
    'e_rosenbrock': extended_rosenbrock.create,
    'e_fr': extended_fr.create,
}


def run_benchmark(name, method_name, create, optimize, n):
    """
    Run a single testcase

    :param name: objective function name
    :param method_name: optimizer name
    :param create: function constructor
    :param optimize: optimizer
    :param n: dimensionality
    """
    print("%s (n = %d), %s" % (name, n, method_name))
    x0, f0, g0, h0 = create(n)
    f, g, h, fc, gc, hc = call_counter.wrap(f0, g0, h0)
    x, it_n, it_ls, msg = optimize(f, g, h, x0, 1000, 1e-5)
    optimizer_util.show_result(f0, g0, x, it_n, it_ls, msg, fc, gc, hc, method_name)


def main():
    m_name = sys.argv[1]
    f_name = sys.argv[2]
    n = int(sys.argv[3])
    fun = FUNCTION_BUILDERS[f_name]
    optimizer = METHODS[m_name]
    run_benchmark(f_name, m_name, fun, optimizer, n)


if __name__ == '__main__':
    main()
